{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Introduction to Matplotlib" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "skip" } }, "source": [ "Now that we can start doing serious numerical analysis with Numpy arrays, we also reach the stage where we can no longer print out hundreds or thousands of values, so we need to be able to make plots to show the results." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The **Matplotlib** package can be used to make scientific-grade plots. You can import it with:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "If you are using IPython and you want to make interactive plots, you can start up IPython with:\n", "\n", " ipython --matplotlib\n", "\n", "If you now type a plotting command, an interactive plot will pop up.\n", "\n", "If you use the Jupyter Notebook, add a cell containing:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%matplotlib inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "and the plots will appear inside the notebook." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Basic plotting" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "The main plotting function is called ``plot``:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.plot([1,2,3,6,4,2,3,4])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the above example, we only gave a single list, so it will assume the x values are the indices of the list/array." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "However, we can instead specify the x values:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.plot([3.3, 4.4, 4.5, 6.5], [3., 5., 6., 7.])" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Matplotlib can take Numpy arrays, so we can do for example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "x = np.linspace(0., 10., 50)\n", "y = np.sin(x)\n", "plt.plot(x, y)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "The ``plot`` function is actually quite complex, and for example can take arguments specifying the type of point, the color of the line, and the width of the line:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.plot(x, y, marker='o', color='green', linewidth=2)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "The line can also be removed:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.plot(x, y, marker='o', color='green', linewidth=0)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "If you are interested, you can specify some of these attributes with a special syntax, which you can find more about in the [Matplotlib](https://matplotlib.org/) documentation. Also, check out the Matplotlib webpage for examples of what is possible with this powerful package. For most plots this is probably all you will ever need." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.plot(x, y, 'go') # shortcut for green and circles" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exercise 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We start by loading the ``data/munich_temperatures_average_with_bad_data.txt`` file which we encountered in the introduction to Numpy:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# The following code reads the file and removes bad values\n", "date, temperature = np.loadtxt('data/munich_temperatures_average_with_bad_data.txt', unpack=True)\n", "keep = np.abs(temperature) < 99\n", "date = date[keep]\n", "temperature = temperature[keep]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now that the data has been read in, plot the temperature against time:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# your solution here" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, try plotting the data against the fraction of the year (all years on top of each other). Note that you can use the ``%`` (modulo) operator to find the fractional part of the dates." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# your solution here" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Other types of plots" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Scatter plots" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "While the ``plot`` function can be used to show scatter plots, it is mainly used for line plots, and the ``scatter`` function is more often used for scatter plots, because it allows more control of the markers." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = np.random.random(100)\n", "y = np.random.random(100)\n", "plt.scatter(x, y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Histograms" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Histograms are easy to plot using the ``hist`` function:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.hist?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "v = np.random.uniform(0., 10., 100)\n", "h = plt.hist(v, bins=[0,2,4,6,8,10], density=True) # we do h= to capture the output of the function, but we don't use it (here)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Images" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "You can also show two-dimensional arrays with the ``imshow`` function. Note that this function requires a regular mesh as in pixels of a picture. If you have unregulaly meshed data, try the function ``pcolormesh`` ([more info here](https://matplotlib.org/api/_as_gen/matplotlib.pyplot.pcolormesh.html))." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "array = np.random.random((64, 64))\n", "plt.imshow(array)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "And the colormap can be changed (see [here](https://matplotlib.org/examples/color/colormaps_reference.html) for default colormaps available in Matplotlib):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.imshow(array, cmap='magma')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Contours" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Often, countour plots come in handy when illustrating 3D data. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = y = np.arange(-2.0, 2.0, 0.005)\n", "X, Y = np.meshgrid(x, y)\n", "Z = np.exp(-X**2 - Y**2)\n", "\n", "plt.axes().set_aspect('equal') # we want an equal aspect ratio such that you see we are plotting \"circles\"\n", "\n", "CS = plt.contourf(X, Y, Z, cmap='viridis')\n", "cbar = plt.colorbar(CS)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also add contour lines and labels (more on customozing plots with labels etc. later):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.axes().set_aspect('equal')\n", "\n", "CS = plt.contourf(X, Y, Z, cmap='viridis')\n", "cbar = plt.colorbar(CS)\n", "cbar.ax.set_ylabel('Label for colorbar')\n", "\n", "CS = plt.contour(X, Y, Z, colors='white')\n", "plt.clabel(CS, inline=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the above, we used the ``np.meshgrid`` function which is very useful when the plotting functions (and also other functions in general) require the ``X`` and ``Y`` coordinates in a special format. To understand the ``np.meshgrid`` function better, consider the following example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "# For example:\n", "x = [1,2,3]\n", "y = [1,2]\n", "a, b = np.meshgrid(x, y)\n", "\n", "print(np.shape(a), np.shape(b))\n", "print(a)\n", "print(b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So for each of the chosen ``x`` and ``y`` points, ``a`` and ``b`` contain the values of ``x`` and ``y``, respectively." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "# at coordinate (0|1), we have (note: the first index fixes y, the second x)\n", "print(x[0], y[1], a[1][0], b[1][0])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Field lines" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For a **vector field**, you can plot a depiction of the field lines with ``plt.streamplot``\n", "\n", "Here, we do this for the following field in the xy-plane\n", " $$\\vec{K}(\\vec{r})=\\vec{K}(x,y,z) = (-y,x,0) = \\vec{e}_z \\times \\vec{r}$$\n", " \n", "We again use ``np.meshgrid`` to obtain the elements of $\\vec{K}$ in the right format for the ``plt.streamplot`` function. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = np.arange(-10, 10, 0.1)\n", "y = np.arange(-10, 10, 0.1)\n", "\n", "xx, yy = np.meshgrid(x, y)\n", "\n", "kx = -yy\n", "ky = xx\n", "\n", "plt.axes().set_aspect('equal')\n", "plt.streamplot(x, y, kx, ky, color='k')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Customizing plots" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "You can also customize plots. For example, the following code adds axis labels, and sets the x and y ranges explicitly:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "x = np.random.random(100)\n", "y = np.random.random(100)\n", "\n", "plt.scatter(x, y)\n", "\n", "plt.xlabel('x values')\n", "plt.ylabel('y values')\n", "\n", "plt.xlim(0., 1.)\n", "plt.ylim(0., 1.)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Saving plots to files" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "To save a plot to a file, you can do:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = np.random.random(100)\n", "y = np.random.random(100)\n", "\n", "plt.scatter(x, y)\n", "\n", "plt.xlabel('x values')\n", "plt.ylabel('y values')\n", "\n", "plt.xlim(0., 1.)\n", "plt.ylim(0., 1.)\n", "\n", "plt.savefig('my_plot.png', dpi=300)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This has created the PNG file 'my_plot.png' and you can then view the resulting file like you would view a normal image. On Linux, you can run the following on the command line:\n", "\n", " $ eog my_plot.png\n", "\n", "(or pick another image viewer than 'eog')." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note: there are many more options to save figures. I would always recommend to save plots as \"vector\" graphics, e.g. as PDF files unless the plot contains many datapoints such that the PDF file would be too large. In such cases (e.g. data from big simulations containing millions of datapoints), use PNG files but increase the resolution by providing the ``dpi=300`` argument (dpi = dots per inch) to ``plt.savefig``. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Interactive plotting" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "One of the features of Matplotlib is the ability to make interactive plots where you can, e.g., zoom in and out, set labels, save the plot to files etc. When using IPython, you can do:\n", "\n", " %matplotlib qt\n", " \n", "to change the backend to be interactive, after which plots are interactive (this won't work within a Jupyter/IPython notebook)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Learning more" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "skip" } }, "source": [ "The easiest way to find out more about a function and available options is to use the ``?`` help in IPython:\n", "\n", " In [11]: plt.hist?\n", "\n", " Definition: plt.hist(x, bins=10, range=None, normed=False, weights=None, cumulative=False, bottom=None, histtype='bar', align='mid', orientation='vertical', rwidth=None, log=False, color=None, label=None, stacked=False, hold=None, **kwargs)\n", " Docstring:\n", " Plot a histogram.\n", "\n", " Call signature::\n", "\n", " hist(x, bins=10, range=None, normed=False, weights=None,\n", " cumulative=False, bottom=None, histtype='bar', align='mid',\n", " orientation='vertical', rwidth=None, log=False,\n", " color=None, label=None, stacked=False,\n", " **kwargs)\n", "\n", " Compute and draw the histogram of *x*. The return value is a\n", " tuple (*n*, *bins*, *patches*) or ([*n0*, *n1*, ...], *bins*,\n", " [*patches0*, *patches1*,...]) if the input contains multiple\n", " data.\n", "\n", " etc.\n", "\n", "But sometimes you don't even know how to make a specific type of plot, in which case you can look at the [Matplotlib Gallery](https://matplotlib.org/gallery.html) for example plots and scripts, or search the internet.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exercise 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "1. Use Numpy to generate 10000 random values following a Gaussian/Normal distribution, and make a histogram. Try changing the number of bins to properly see the Gaussian. Try overplotting a Gaussian function using a colored line, and adjust the normalization such that the histogram and the line are aligned.\n", "\n", "2. Do the same for a Poisson distribution. Compare the Poisson distribution for expectation values $\\lambda<15$ with the appropriate Gaussian." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# your solution here" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exercise 3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Work out the magnetic field lines of two equal but infinite line currents along the z-axis that are separated by a distance $a$ from the y-axis.\n", "\n", "Since the streamlines are scaled, one can drop constants.\n", "\n", "The $\\vec{B}$-Field of a single line current $I$ is\n", "$$\\vec{B} (\\vec{r})= \\frac{\\mu_0 I}{2 \\pi} \\frac{1}{|\\vec{r}|} \\vec{e}_{\\varphi}$$\n", " \n", "**Only** if time permits: Can you plot the magnetic fieldlines in the xy-plane for a circular coil with radius $a$ in the xz-plane?\n", "\n", "The Biot-Savart law for a wire element $\\mathrm{d}\\vec{l}$ is\n", "\n", "$$\\mathrm{d}\\vec{B} (\\vec{r})= \\frac{\\mu_0 I}{4 \\pi} \\frac{\\mathrm{d} \\vec{l} \\times \\vec{r}}{|\\vec{r}|^3}$$\n", "\n", "where $\\vec{r}$ is the vector from the current element to the place of measurement." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "# your solution here\n" ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.4" } }, "nbformat": 4, "nbformat_minor": 1 }